Skip to content

feat: add Upload-Post integration for social media publishing#7

Open
mutonby wants to merge 1 commit into
calesthio:mainfrom
mutonby:feat/uploadpost-social-publishing
Open

feat: add Upload-Post integration for social media publishing#7
mutonby wants to merge 1 commit into
calesthio:mainfrom
mutonby:feat/uploadpost-social-publishing

Conversation

@mutonby

@mutonby mutonby commented Apr 5, 2026

Copy link
Copy Markdown

Summary

Adds an uploadpost_publisher tool that lets OpenMontage publish finished videos, photos, documents, and text posts directly to 11 social platforms from the publish pipeline stage — no extra code, no per-platform OAuth setup.

Supported platforms: Instagram, TikTok, YouTube, LinkedIn, Facebook, X (Twitter), Threads, Pinterest, Bluesky, Reddit, Google Business Profile.

How it works

  1. Users create a free account at upload-post.com — no credit card required.
  2. Connect social accounts in the dashboard with two clicks — no need to create developer apps, generate tokens, or configure OAuth per platform.
  3. Set UPLOADPOST_API_KEY in .env.
  4. The uploadpost_publisher tool is auto-discovered by the registry and becomes available in every pipeline's publish stage.

Free tier: 10 uploads/month across all platforms.

What's included

  • tools/publishers/uploadpost_publisher.py — Full BaseTool implementation with:

    • Video upload (POST /api/upload)
    • Photo/carousel upload (POST /api/upload_photos)
    • Document upload for LinkedIn (POST /api/upload_document)
    • Text-only posts (POST /api/upload_text)
    • Async upload with status polling
    • Scheduling (scheduled_date) and queue support (add_to_queue)
    • dry_run() preflight checks
    • Platform-specific params (Facebook pages, Pinterest boards, LinkedIn pages, Instagram stories, first comment)
  • skills/core/social-publishing.md — Layer 2 skill doc for agents

  • All 10 pipeline publish stages updated with uploadpost_publisher in tools_available

  • All 10 publish-director skills updated with "Direct Publishing" section

  • .env.example updated with UPLOADPOST_API_KEY

  • skills/INDEX.md updated with social_publishing capability family

Integration architecture

Pipeline publish stage
  → uploadpost_publisher.execute()
    → POST /api/upload (video) or /upload_photos or /upload_text or /upload_document
    → Poll GET /api/uploadposts/status until FINISHED
    → Return ToolResult with post URLs per platform
      → Maps to publish_log schema entries

The tool follows the same patterns as existing API tools (e.g., veo_video): env-based API key, get_status() check, estimate_cost(), dry_run(), retry policy, and idempotency keys.

Test plan

  • Tool imports and instantiates correctly
  • Auto-discovered by registry.discover() (appears in 67-tool list)
  • Shows in capability_catalog() under social_publishing
  • Shows in provider_menu() with install instructions
  • dry_run() correctly reports missing API key and missing files
  • Status is unavailable without API key, available with it
  • End-to-end publish with a real API key (requires Upload-Post account)

API docs: https://docs.upload-post.com

🤖 Generated with Claude Code

Add uploadpost_publisher tool that publishes finished videos, photos,
documents, and text to 11 social platforms (Instagram, TikTok, YouTube,
LinkedIn, Facebook, X, Threads, Pinterest, Bluesky, Reddit, Google
Business) via a single API call through Upload-Post.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@mutonby mutonby requested a review from calesthio as a code owner April 5, 2026 23:13
@mutonby

mutonby commented Apr 9, 2026

Copy link
Copy Markdown
Author

@calesthio I think it's the missing piece to complete the picture. Let me know if you have any questions.

@PacemakerX

Copy link
Copy Markdown

This is a good initiative @mutonby.

jahai added a commit to jahai/OpenMontage that referenced this pull request May 9, 2026
…alesthio#8 from Phase 2 lessons

Banks two patterns that surfaced during Phase 2. Real Phase-3+
discipline value; both now documented as canonical AUDIT_PATTERNS
reference.

Pattern calesthio#7: Test infrastructure must accommodate derived IDs.
- Default gate satisfied: multiple Phase 2 test files hit the issue
  (test_audit_consult.py orphan YAMLs, test_audit.py needing
  cascading_delete with synthetic IDs, test_thumbnails.py similar,
  test_vision_anthropic.py with TRACKED_API_CALL_IDS).
- Production ID derivation is correct (deterministic, content-aware,
  collision-resistant) but makes IDs test-hostile. ~80 lines of
  cleanup logic for ~7 audit-consult tests; growing with each new
  Wave-B-related test suite.
- Rule: modules that derive IDs internally must accept _id_override
  keyword-only param (FOR TESTING ONLY). Tests pass test-prefixed
  IDs; cascading_delete handles cleanup uniformly.
- v0.6 amendment landed _id_override on audit.create_audit_session
  + audit.capture_verdict; Pattern calesthio#7 names the discipline
  canonically so future Phase 3+ derived-ID modules opt in.

Pattern calesthio#8: Content-matching specification must be tightened against
project-specific content (preventive promotion per gate amendment).
- v0.6 review caught _SAFETY_REFUSAL_RE matching legitimate critical
  evaluations ("I cannot recommend this for hero promotion because
  the apparatus geometry is unclear"). Single occurrence; promoted
  preventively because the failure surface is broader than the
  single bug.
- Promotion note explicit: future content-matching specifications
  (rubric criteria parsing, future provider-specific refusal patterns
  when Perplexity / ChatGPT / Gemini adapters land, cross-AI capture
  relevance-binding heuristics, filepath-pattern recovery in walker)
  face the same risk class against the same project content domain
  (H#3 reenactment, addiction themes, behavioral-conditioning
  register).
- Rule: third bucket of test cases mandatory — "looks-like-target-
  but-isn't" cases drawn from project content. Generic positive +
  generic negative + project-specific-negative.
- Verb-aware patterns over blanket prefix matching where applicable
  (per _SAFETY_REFUSAL_RE tightening precedent).

Updated timestamp banks the v0.7 amendment of the discipline doc
itself.

Tests: 16/16 still green (doc-only change).

Phase 2 acceptance bridge gate unchanged: rubric authoring + one
real Wave B firing still required before Phase 3 Wave 1 code starts.
This is preparatory discipline-banking work that compounds for
Phase 3+ test infrastructure.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jahai added a commit to jahai/OpenMontage that referenced this pull request May 13, 2026
…forcement calesthio#3 + Banking principle calesthio#7 + Phase 2.5 conftest fix promoted to MUST-DO

Five additions documenting the cleanup-leak class surfaced in this
session's diagnostic side-thread:

1. New Pattern calesthio#8 reinforcement entry calesthio#3 — test cleanup leak class.
   Two confirmed instances (test_audit_sessions audit_sessions leak +
   test_vision_anthropic api_calls leak). Pattern: when test scope
   assumes "I know all the IDs I created" but production code creates
   derivative rows from test-injected data with its own SHA-derived IDs,
   cleanup silently leaves rows behind.

2. New Banking principle calesthio#7 — test isolation should be enforced at
   fixture level, not at cleanup discipline. Surfaces only when
   production queries (cost rollups, /healthz banners) become polluted
   enough to notice.

3. Phase 2.5 conftest+tmp_path fix promoted from deferred-candidate
   to MUST-DO before Wave 1 code starts. Added new entry at top of
   "Phase 3 territory" section with estimate (~2-4 hours), scope
   (16 existing test suites to migrate), and verification approach
   (state.db row count assertions before/after).

4. Updated existing "Test runner quirk" section's Phase 2.5 reference
   to point at the new MUST-DO framing instead of the prior deferred
   framing — keeps the doc internally consistent.

5. Updated header to reflect cleanup-leak class banking + a52ec90
   api_calls cleanup commit reference.

References: companion commit a52ec90 (api_calls cleanup execution).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jahai added a commit to jahai/OpenMontage that referenced this pull request May 15, 2026
Eliminates the cleanup-leak class (Pattern calesthio#8 reinforcement calesthio#3 /
Banking principle calesthio#7) structurally by isolating test writes to
tmp_path. Tests never touch production _data/state.db. Replaces
the cleanup-discipline pattern (TRACKED_*_IDS + cascading_delete
prefix) with fixture-level isolation.

- migrations/env.py: TOOL_BUILD_ALEMBIC_URL env var override
  (conftest uses it to point Alembic at tmp_path during the
  template-DB construction).
- tests/conftest.py (new): session-scoped template DB built once
  via Alembic upgrade head; per-test autouse isolated_db fixture
  copies the template, builds the canonical _data/ tree under
  tmp_path/projects/latent_systems/tool_build/, patches
  db.{DB_PATH,DATA_DIR,REPO_ROOT,TOOL_BUILD_DIR}, patches the 5
  dependent-module snapshots (runtime, router_tail, retry_queue,
  thumbnails, watcher), auto-seeds tool-grammar configs from
  seeds/*.yaml.
- 15 test files: `def test_main(): assert main() == 0` wrapper
  added before if __name__ block. Standalone
  `python tests/test_X.py` invocation preserved (uses production
  _data/, original cleanup-discipline behavior — fixture only
  applies under pytest).
- 3 test files (test_audit_consult, test_thumbnails,
  test_vision_anthropic): module-level TEST_DIR snapshot replaced
  with _test_dir() function for lazy db.DATA_DIR evaluation.
- test_router_tail.py: test_ingest_roundtrip renamed
  _ingest_roundtrip (pytest discovery + repo_root fixture
  mismatch); test_main skipped with rationale — real-repo
  integration test covered by standalone path.
- SESSION_STARTER.md state-check step 4: script-loop → pytest.

Verification: full suite 94 passed + 1 documented skip;
production state.db row counts byte-identical pre/post. ~13s
suite runtime (vs ~5s prior script-loop; isolation overhead
acceptable). Phase 2.5 conftest non-negotiable item per Day 1
of sprint: COMPLETE.
jahai added a commit to jahai/OpenMontage that referenced this pull request May 15, 2026
…ic action + audio assets

Three deliverables landed on Day 2 of the 7-day Phase 3 complete-the-
app sprint, all additive and verified via the Day 1 isolated_db
fixture (full suite 96 passed + 1 documented skip; production
state.db row counts byte-identical pre/post pytest run).

**Migration 0004** (additive — no temp-table-and-copy):
- notes_md_state (new) — F6 NOTES.md authorship state per
  phase3_design_notes.md v0.2 schema sketch.
- cross_ai_captures ALTER + 7 columns + 2 indexes — F7 cross-AI
  capture expansion per v0.2 design.
- hero_promotions ALTER + 4 nullable columns (verdict_id,
  promoted_at, promoted_by, audit_session_id) — gap closure between
  F5_MODAL_UX_DRAFT.md INSERT shape and v0.2 schema sketch which
  didn't include them. Existing 3 production rows survive without
  backfill; F5 enforces non-null at application layer.
- audio_assets (new) — rough-cut player prereq (Days 4-5). Tracks
  narration mp3 files (EP1_section_N_para_P_voice_X<val>_take<N>.mp3)
  with section + paragraph + variant + voice_profile + hash +
  is_canonical for player playlist construction.
- constants.SUPPORTED_SCHEMA_VERSIONS extended to {0001..0004}.

**F5 hero promotion atomic action** per F5_MODAL_UX_DRAFT.md v1.2:
- dispatcher.hero_promote() — atomic file-COPY + DB-INSERT
  transaction. Step 3 (F6 prompt fire) deferred (F6 lands Day 3);
  graceful-degradation status 'deferred_f6_not_shipped'.
- dispatcher.hero_un_promote() — atomic file-MOVE
  (winners/ -> _DEPRECATED_<sanitized>/) + DB-UPDATE. Reason
  >= 5 chars + filesystem-safe sanitization per channel staple calesthio#12.
- POST /audit/render/<id>/promote + /un_promote endpoints in
  app.py with 400/404/409/500 mapping based on error class.
- tests/test_hero_promotion.py — 14 scenarios covering positive,
  project-specific looks-like-target-but-isn't (weak verdict,
  no section, winners/ auto-create, path-traversal sanitization),
  and negative (no render, no verdict, already-promoted, no
  active promotion, sanitized-to-empty reason).
- Modal UI deferred to Day 6 per original Wave 1 plan.

**Audio asset first-class state.db support** (rough-cut player
prereq):
- audio_assets.py module: parse_audio_filename, ingest_audio_file
  (idempotent on hash), rebuild_audio_cache (walks canonical
  voice-profile tree, skips load-bearing validation filenames +
  archived/_DEPRECATED_ paths), get_audio_assets_for_section
  (paragraph-ordered, canonical_only filter), set_canonical_variant
  (exclusive within slot).
- tests/test_audio_assets.py — 12 scenarios.

**Cascade order fix:** db.py _CASCADE_DELETE_ORDER hero_promotions
+ verdicts entries extended to `id LIKE ? OR render_id LIKE ?`
because hero_promote derives hashed promotion_id (Pattern calesthio#7 —
derived IDs don't carry test prefixes; OR-on-render_id catches
test-prefixed renders' promotions). conftest.py _ARTIFACT_SUBDIRS
extended with notes_md_state + audio_assets.

state.db.pre_0004_backup written locally before migration (per
migration boilerplate); NOT committed (local-only insurance).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants